metinfo 6.2 任意文件上传
Contents
前言
昨天复现了 metinfo 6.2.0 的一个前台任意文件上传的漏洞,发现了一些其他利用方式~
代码审计
为了复现该漏洞,所以搭建环境如下。
windows + php 5.3.29
安装完该 cms 后,我先从前台首页跟了一遍代码的执行流程,大致熟悉了一下路由的规则。
index.php
1 | define('M_NAME', 'index'); |
跟进 /app/system/entrance.php 。
文件最后调用了 load::module(),其中调用了 self::_load_class() 去调用相应类的相应方法。
1 | public static function module($path = '', $modulename = '', $action = '') { |
因为漏洞发生在 uploadify 类的 doupfile 方法中,找了一下发现可以路由到该方法的文件为 admin/index.php。在该文件开头设置了一个常量。
1 | define('IN_ADMIN', true); |
该常量和 gpc 中数据的过滤逻辑相关。在 metinfo 中有一个全局变量 $_M,其中的 form 键对应的值为 gpc 中的数据。
因为设置了常量 IN_ADMIN 的值,所以这里不会对 gpc 中数据调用 sqlinsert 函数进行处理,这样就不会把\
转换成/
了,这和后面的参考文章的 payload 有关。
接着回到 uploadify 类中,因为 uploadify 类继承自 web 类,其构造方法中调用了 web 类的构造方法,web 类是一个前台基类,所以并没有做权限相关的验证。根据上面的分析,已经可以路由到触发漏洞的 doupfile 方法中。
在 /app/system/include/module/uploadify.class.php。
这里 savepath 和 is_rename 都是 gpc 中的数据,我们可控,跟进 upload 方法。
1 | public function upload($formname){ |
其中调用了 /app/system/include/class/upfile.class.php 中的 upload 方法。
我把需要注意的地方圈起来了,自己跟一遍,大致就能发现构造 payload 的难点,第一个是文件后缀名的限制,第二个是目录名的限制。
先说一下文件后缀名的限制,文件名在上传前经过了 iconv 函数的处理,而文件名是 savepath 和 savename 属性拼接来的,这两个属性都是我们可控的。而 iconv 这个函数在 php < 5.4 中是存在截断问题的。
iconv 截断:https://www.cnblogs.com/milantgh/p/3602141.html
所以我们可以构造类似a.php%80.jpg
这样的文件名,绕过文件后缀名的限制,但是因为在前面的 set_savename 函数中,会将 savename 属性中最后一个点.
之前的多余的点.
替换成_
,所以截断的 payload 需要放在 savepath 属性中,在最后和 savename 拼接文件名的时候形成类似a.php%80.jpg
这样的文件名,然后进入 iconv 函数,截断后变成a.php
,从而绕过后缀名的检测。
所以我们的重点就放在了 savepath 属性上。在一开始触发漏洞的 doupfile 函数中,设置了 savepath 属性的值。
实际上,savepath 属性的值是PATH_WEB.'/upload'.xx.'/'
,最后的/
是在 path_standard 函数中加上的,其中 xx 是我们传参中 savepath 对应的值。这里要注意就是 savepath 结尾字符一定是/
。
回到 upload 方法,可以知道 savepath 属性需要满足以下要求。
- 以
PATH_WEB. 'upload/'
开头(已满足) - 不含
./
- 进入 makedir 函数返回 true
跟进 makedir 函数。
这里的逻辑就是会递归创建 savepath 指定的目录,如果成功则返回 true。
我们重新理一下整个思路:
- 路由到 uploadify 类的 doupfile 方法中。
- 上传文件名的后缀在白名单中,如
a.jpg
,该值存放在 savename 属性中;将截断 payload 放在 savepath 参数中,如shell.php%80
,在给 savepath 属性赋值的时候会拼接绝对路径,此时 savepath 属性的值为PATH_WEB.'upload/'.'shell.php%80'.'/'
。 - savepath 属性和 savename 属性拼接成文件名 file_name,即
webroot/upload/shell.php%80/a.jpg
,进入 iconv 函数,截断后变成webroot/upload/shell.php
,成功上传文件至 upload 目录。
这里唯一需要注意的,就是 savepath 属性在进入 makedir 函数创建目录时,因为其目录名中存在特殊字符,所以可能会因为创建失败而返回 false。
windows 目录名与 gbk
当使用 %80 在 iconv 函数中截断后缀时,%80 经过 url 解码成特殊字符。
此时进入 makedir 函数的 savepath 属性值为webroot/upload/shell.php�/
(savepath 属性值结尾拼接了/
,我们实际传入的是shell.php%80
)
在 windows 的中文系统中,文件名的默认编码为 gbk,在 linux 中默认编码为 utf-8,这里%80
对应的 gbk 字符可以作为 windows 下的目录名。
gbk 编码:https://www.23bei.com/tool-54.html#
所以该目录名合法,这样就通过了 makedir 的检测,成功上传了文件。
上传的 shell.php 文件因为 iconv 截断,所以是在 upload 目录下,而 makedir 创建的目录只是为了验证 savepath 属性指定的路径可创建,只要 makedir 能创建目录返回 true,就能到 iconv 截断处从而上传文件。
参考文章中
在 iconv 转换字符集时,如果字符串中存在源字符集序列不允许的字符时会造成截断。utf-8 在单字节时允许的范围为 0x00-0x7F。
所以实际上大于等于 %80 的字符都会造成 iconv 函数的截断,而测试发现,除了 %80 以外的单字节字符都无法成为 windows 下的合法目录名,所以在 makedir 创建目录时,就会返回 false,这样就到不了 iconv 截断处了。
因为 windows 下目录分割符可以是\
,所以参考文章中使用..\
来实现目录穿越,这样就会在 file_exists 函数检测时判断目录存在,就不会进入 mkdir 中创建目录。这里需要注意的是,一开始我们说了 gpc 中的数据不会经过 sqlinsert 函数处理,所以\
不会替换成/
,这样在进入 makedir 函数前对 savepath 检测时,就不会检测到./
。将 get 中的 savepath 参数设置为shell.php%81/..\
,发现 file_exists 检测为 false,且 mkdir 无法创建该名字的目录,这就导致了 makedir 返回 false。
测试后发现shell.php%81\..\
可以通过目录跳转使 file_exists 函数返回 true,即 makedir 返回 true。
那还有什么办法让 %80 以外的能造成 iconv 截断的单字节字符,能通过 makedir 函数对目录名的检测呢?
回想一下,sql 中的宽字节注入。当数据库编码是 gbk 且单引号被转义时,在单引号前面输入 %df,即1%df\'
,这样进入数据库时,单字节%df
和反斜线对应的单字节%5c
,组成双字节df5c
,即運
,这样单引号就成功逃逸了。
同理,因为 windows 中目录名以 gbk 编码,所以假如我们使用任意大于等于 %80 的其他字符触发 iconv 截断,如 %88,而在 makedir 创建目录时,%88 对应的字符不合法。但因为 gbk 编码范围为 8140 - FEFE,所以我们可以在后面拼接一个单字节,和 %88 组成双字节后成为合法 gbk 字符,这样就可以创建 savepath 指定的目录了。
这样就通过了 makedir 的检测,并成功上传了文件。
可以看一下885c
对应的 gbk 字符,和目录名中的字符是一样的。
在这个场景中,上传文件所在的目录与 makedir 创建的目录不是一个目录,所以 gbk 字符并不影响我们使用 webshell,但是如果 shell 文件在 makedir 创建的目录下的话,因为目录名中带有 gbk 字符,所以是不能直接访问到的。
总结
该漏洞的触发需要在 windows 条件下,且 php < 5.4,这样才能利用 iconv 截断的特性去控制文件后缀,还有就是 savepath 指定的 windows 目录名要合法,可以通过\..\
实现目录穿越绕过 file_exists 函数的检测,或者可以通过组合 gbk 字符使目录可创建。
ref :
https://xz.aliyun.com/t/5603
http://www.yulegeyu.com/2019/06/18/Metinfo6-Arbitrary-File-Upload-Via-Iconv-Truncate/
https://www.qqxiuzi.cn/zh/hanzi-gbk-bianma.php
https://www.cnblogs.com/milantgh/p/3602141.html
https://www.23bei.com/tool-54.html#
Author: ll
Link: http://yoursite.com/2019/07/12/metinfo 6.2 任意文件上传/
License: 知识共享署名-非商业性使用 4.0 国际许可协议